<?php
namespace Core\Datastorage;

use Core as Core;

require_once(DATASTORAGE_DIR . 'mapping.class.php');
require_once(DATASTORAGE_DIR . 'expression.class.php');
require_once(DATASTORAGE_DIR . 'property.class.php');

/**
* Session class definition. This class manage database access and SQL generated to send at the database.
*
* @author Didelot Guillaume
* @version 1.0.0
* @copyright Copyright (c) 2015, Didelot Guillaume
*
* @method Parameters Singleton()
* @method void Open()
* @method void Close()
* @method object Load($entity, $id)
* @method void CreateCriteria($entity)
* @method void AddCriteria($expression)
* @method object UniqueResult()
* @method array ListResult()
* @method object Save($object)
* @method object Update($object)
* @method boolean Delete($object)
* @method string GetTable()
* @method string GetPrimaryKey()
* @method string GetColumn($property)
* @method array GetProperties()
* @method string GetPropertyType($property)
* @method string GetJoints()
* @method string GetColumns()
* @method string GetColumnNameWithAlias($columnName)
* @method string GetCriterias()
* @method array ExecuteListSQL()
* @method object ExecuteSQL()
*/
class Session {
	
	/**
	* @property string $Server The server address
	*/
	private $Server;
	
	/**
	* @property string $DataBaseName The database name
	*/
	private $DataBaseName;

	/**
	* @property string $Login The database user login name
	*/
	private $Login;
	
	/**
	* @property string $Password The database user password
	*/
	private $Password;
	
	/**
	* @property datetime $CreationDate The creation date of the session
	*/
	private $CreationDate;
	
	/**
	* @property MysqlConnection $Connection The MySQL connection
	*/
	private $Connection;
	
	/**
	* @property array $Mapping The mappings parsed for the application
	*/
	private static $Mapping;
	
	/**
	* @property object $CurrentEntity The current entity
	*/
	private $CurrentEntity;
	
	/**
	* @property array $Criterias The current criterias, it's an array of Expression
	*/
	private $Criterias;
	
	/**
	* @property string $Criterias The current query
	*/
	private $CurrentQuery;
	
	/**
	* @property Mapping $CurrentMapping The current mapping targeted
	*/
	private $CurrentMapping;
	
	/**
	* @property string $OrderByPart The order by part
	*/
	private $OrderByPart;
	
	/**
	* @property Session $instance The session instance
	*/
	private static $instance;
	
	/**
	* The default constructor
	*/
	private function __construct() 
	{
		$parameters = Core\CoreCommons\Parameters::Singleton();
		$database = $parameters::Get("database");

		$this->Server = $database->host;
		
		if(!isset($this->Server) || trim($this->Server)==='')
		{
			throw new \Exception("The server name on parameter fil have to be fill.");
		}
		
		$this->DataBaseName = $database->databasename; 
		
		if(!isset($this->DataBaseName) || trim($this->DataBaseName)==='')
		{
			throw new \Exception("The database name on parameter fil have to be fill.");
		}
		
		$this->Login = $database->login;
		
		if(!isset($this->Login) || trim($this->Login)==='')
		{
			throw new \Exception("The login name on parameter fil have to be fill.");
		}
		
		$this->Password = $database->password;
		$this->CreationDate = date("Y-m-d H:i:s");
	}

	/**
	* The singleton method
	*
	* @todo set the mapping parsed on a session variable
	*
	* @return Session Return a session instance
	*/
	public static function Instance() 
	{
		$result = null;
		try
		{
			$c = __CLASS__;
			self::$instance = new $c;
			$result = self::$instance;
			self::$Mapping = Mapping::Singleton()->getMappingFiles();
		}
		catch(\Exception $ex)
		{
			Core\CoreCommons\Logger::Error($ex->getMessage());
		}

		return $result;
	}
	
	/**
	* Open the connection
	*/
	public function Open()
	{
		if($this->Connection == null)
		{
			Core\CoreCommons\Logger::Info("Open connection $this->Server, $this->Login");
			
			$this->Connection = mysql_connect($this->Server, $this->Login, $this->Password); 
			
			if (!$this->Connection)
			{
				Core\CoreCommons\Logger::Error("Unable to open a connection $this->Server, $this->Login, $this->Password");
				die ("Unable to open a connection $this->Server, $this->Login, $this->Password"); 
			}
			
			if(!mysql_select_db($this->DataBaseName))
			{
				Core\CoreCommons\Logger::Warning("Unable to select the database $this->DataBaseName");
			}
			
			mysql_query("SET NAMES 'utf8'"); 
		}
	}
	
	/**
	* Close the connection
	*/
	public function Close()
	{
		Core\CoreCommons\Logger::Info("Close connection");
		$this->OrderByPart = null;
		mysql_close($this->Connection);
		$this->Connection = null;
	}
	
	/**
	* Load a model object form his type name and his primary key
	*
	* @param object $entity Model object 
	* @param integer $id The primary key 
	*
	* @return The model object
	*/
	public function Load($entity, $id)
	{
		if($entity == null || $entity == "")
		{
			throw new \Exception("Session - Load => The entity parameter is null.");
		}
		
		if($id == null || $id == "")
		{
			throw new \Exception("Session - Load => The id parameter is null.");
		}
		
		Core\CoreCommons\Logger::Debug("Load $entity with $id");
		
		$this->CurrentEntity = $entity;
		
		$mapping = self::$Mapping[$this->CurrentEntity];
		
		$this->CurrentMapping = $mapping;
		
		$table = $this->GetTable();
		
		$primaryKey = $this->GetPrimaryKey();
		
		$this->CurrentQuery = sprintf('select * from %s where %s=%u', $table, $primaryKey, $id);
		
		Core\CoreCommons\Logger::Debug("Load query : " . $this->CurrentQuery);

		$result = mysql_query($this->CurrentQuery);
		
		if($result == false)
		{
			throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
		}
		
		//Evaluate the number of result
		$numberResult = mysql_num_rows($result);
		
		Core\CoreCommons\Logger::Debug("There is  $numberResult impacted row(s)");
		
		$response = null;
		
		if($numberResult > 1)
		{
			throw new \Exception("The result contains more than 1 row.");
		}
		
		if($numberResult > 0)
		{
			$row = mysql_fetch_assoc($result);
			$ref = new \ReflectionClass("Core\CoreContracts\\" . $this->CurrentEntity); 
			$objectProperties = $ref->getProperties(\ReflectionProperty::IS_PUBLIC);
			$object = $ref->newInstanceArgs();
			/*
			for($i = 0; $i <= (count($objectProperties) - 1); $i++)
			{
				$objectProperty = $objectProperties[$i];
				//If column type is blob set base64_encode threatment
				if($this->GetPropertyType($objectProperty) == "blob")
				{
					$objectProperty->setValue($object, base64_encode($row[$objectProperty->name]));
				}
				else
				{
					$objectProperty->setValue($object, $row[$objectProperty->name]);
				}
			}
			*/
			for($i = 0; $i <= (count($objectProperties) - 1); $i++)
			{
				$objectProperty = $objectProperties[$i];
				$property = $this->CurrentMapping->Properties[$objectProperty->name];
				if($property->IsComplex == false)
				{
					//If column type is blob set base64_encode threatment
					if($this->GetPropertyType($objectProperty) == "blob")
					{
						$objectProperty->setValue($object, base64_encode($row[$objectProperty->name]));
					}
					else
					{
						$objectProperty->setValue($object, $row[$objectProperty->name]);
					}
				}
				else
				{
					Core\CoreCommons\Logger::Info("ExecuteListSQL - detect a complex property $property->Name");
					
					$complexObjectAlias = $property->Alias;
					$complexObject = $this->SetComplexObjectValues($this->GetPropertyType($objectProperty), $objectProperty->name, $row, $complexObjectAlias);
					$objectProperty->setValue($object, $complexObject);
				}
			}
			$response = $object;
			
			mysql_free_result($result);
		}
		return $response;
	}
	
	/**
	* Create a criteria SQL search 
	*
	* @param object $entity Model object 
	*/
	public function CreateCriteria($entity)
	{
		if($entity == null || $entity == "")
		{
			throw new \Exception("Session - CreateCriteria => The entity parameter is null.");
		}
		
		if(isset(self::$Mapping[$entity]) == false)
		{
			throw new \Exception("Session - CreateCriteria => The mapping $entity was not found.");
		}
		
		$this->CurrentEntity = $entity;
		
		$mapping = self::$Mapping[$this->CurrentEntity];
		
		$this->CurrentMapping = $mapping;
		
		$this->Criterias = array();
		
		$columns = $this->GetColumns();
		
		$this->CurrentQuery = sprintf('select %s from %s %s', $columns, $mapping->Table, $mapping->AliasTable);
	}
	
	/**
	* Add a criteria to the SQL request
	*
	* @param Expression $expression Expression object 
	*/
	public function AddCriteria($expression)
	{
		if($expression == null || $expression == "")
		{
			throw new Exception("Session - AddCriteria => The entity expression is null.");
		}
		
		$mapping = self::$Mapping[$this->CurrentEntity];
		$aliasTable = $mapping->AliasTable;
		
		$expression->LeftPart = sprintf("%s.%s", $aliasTable, $expression->LeftPart);
			
		if(isset($this->Criterias))
		{
			$this->Criterias[] = $expression;
		}
	}
	
	/**
	* Provide a unique result about a request
	*
	* @return object Return a unique result found on the database
	*/
	public function UniqueResult()
	{
		$this->GetJoints();
		
		$this->GetCriterias();
		
		if(isset($this->OrderByPart))
		{
			$this->CurrentQuery .= $this->OrderByPart;
		}
		
		Core\CoreCommons\Logger::Debug("UniqueResult query : " . $this->CurrentQuery);
		
		return $this->ExecuteSQL();
	}
	
	/**
	* Provide a result list from a request
	*
	* @return array Return a list result found on the database
	*/
	public function ListResult()
	{
		$this->GetJoints();
		
		$this->GetCriterias();

		if(isset($this->OrderByPart))
		{
			$this->CurrentQuery .= $this->OrderByPart;
		}

		Core\CoreCommons\Logger::Debug("ListResult query : " . $this->CurrentQuery);

		return $this->ExecuteListSQL();
	}
	
	/**
	* Order result by asc or desc on a field
	*
	* @param string $propertyName the property name to order
	* @param string  $flow asc or desc 
	* @todo Make $flow with an enum
	*/
	public function OrderBy($propertyName, $flow)
	{
		if(isset($propertyName) == false || $propertyName == '')
		{
			throw new \Exception("The property name have to be set.");
		}
		
		if(isset($flow) == false || $flow == '')
		{
			throw new \Exception("The flow have to be set.");
		}
	
		if(isset($this->CurrentMapping) == false)
		{
			throw new \Exception("The current mapping is not set.");
		}
		
		if(isset($this->CurrentMapping->Properties[$propertyName]) == false)
		{
			throw new \Exception("The property $propertyName is not present on the current mapping.");
		}
	
		//Get the property alias
		$property = $this->CurrentMapping->Properties[$propertyName];
		
		if(isset($property) == false)
		{
			throw new \Exception("The property $propertyName is null on the current mapping.");
		}
		
		//Set the order by part
		$this->OrderByPart = sprintf(" order by %s %s", $property->Name . '_' . $property->Alias, $flow);
	}
	
	/**
	* Save the netity to the database
	*
	* @param object $object The object to save
	*
	* @return object Return the added object on the database with his Id
	*/
	public function Save($object)
	{
		if(isset($object) == false)
		{
			throw new \Exception("Session - Save => The object parameter is null.");
		}
		
		$classname = get_class($object);

		if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
			$classname = $matches[1];
		}

		$this->CurrentEntity = $classname;

		$table = $this->GetTable();

		$primaryKey = $this->GetPrimaryKey();

		$this->CurrentQuery = sprintf('insert into %s (', $table);
		
		$class = new \ReflectionClass(get_class($object)); 

		$objectProperties = $class->getProperties(\ReflectionProperty::IS_PUBLIC);

		for($i = 0; $i <= (count($objectProperties) - 1); $i++)
		{
			$objectProperty = $objectProperties[$i];
			
			if($i < count($objectProperties) - 1 && $objectProperty->name != $primaryKey)
			{
				$this->CurrentQuery .= sprintf('`%s`, ', $objectProperty->name);
			}
			else if($objectProperty->name != $primaryKey)
			{	
				$this->CurrentQuery .= sprintf('`%s`) values (', $objectProperty->name);
			}
		}
		
		for($i = 0; $i <= (count($objectProperties) - 1); $i++)
		{
			$objectProperty = $objectProperties[$i];
			
			$type = $this->GetPropertyType($objectProperty);

			if($i < count($objectProperties) - 1 && $objectProperty->name != $primaryKey)
			{
				if($type == "int" || $type == "integer")
				{
					$this->CurrentQuery .= sprintf('%s, ', $class->getProperty($objectProperty->name)->getValue($object));
				}
				else
				{
					$this->CurrentQuery .= sprintf('"%s", ', $class->getProperty($objectProperty->name)->getValue($object));
				}
			}
			else if($objectProperty->name != $primaryKey)
			{	
				if($type == "int" || $type == "integer")
				{
					$this->CurrentQuery .= sprintf('%s)', $class->getProperty($objectProperty->name)->getValue($object));
				}
				else
				{
					$this->CurrentQuery .= sprintf('"%s")', $class->getProperty($objectProperty->name)->getValue($object));
				}
			}
		}
		
		Core\CoreCommons\Logger::Debug("Save query : " . $this->CurrentQuery);
			
		$result = mysql_query($this->CurrentQuery);
		
		if($result == false)
		{
			throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
		}
		
		$object->Id = mysql_insert_id();
		
		return $object;
	}
	
	/**
	* Update the entity to the database
	*
	* @param object $object The object to update
	*
	* @return object Return the updated object on the database
	*/
	public function Update($object, $fieldToUpdate)
	{
		if(isset($object) == false)
		{
			throw new \Exception("Session - Update => The object parameter is null.");
		}
		
		$classname = get_class($object);

		if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
			$classname = $matches[1];
		}

		$this->CurrentEntity = $classname;
		
		$mapping = self::$Mapping[$this->CurrentEntity];
		
		$this->CurrentMapping = $mapping;
		
		$table = $this->GetTable();
		
		$primaryKey = $this->GetPrimaryKey();
		
		$this->CurrentQuery = sprintf('update %s set ', $table);
		
		$class = new \ReflectionClass(get_class($object)); 

		$objectProperties = $class->getProperties(\ReflectionProperty::IS_PUBLIC);
		
		$keys = null;

		if(isset($fieldToUpdate))
		{
			$keys = array_keys($fieldToUpdate);
		}
		
		for($i = 0; $i <= (count($objectProperties) - 1); $i++)
		{
			$objectProperty = $objectProperties[$i];
			
			$property = $this->CurrentMapping->Properties[$objectProperty->name];
			
			$type = $this->GetPropertyType($objectProperty);
			
			if($objectProperty->name != $primaryKey)
			{
				if(isset($fieldToUpdate) == false)
				{
					if($type == "int" || $type == "integer")
					{
						$this->CurrentQuery .= sprintf('%s=%s, ', $objectProperty->name, $class->getProperty($objectProperty->name)->getValue($object));
					}
					else
					{
						if($property->IsComplex == false)
						{
							$this->CurrentQuery .= sprintf('%s="%s", ', $objectProperty->name, $class->getProperty($objectProperty->name)->getValue($object));
						}
						else
						{
							//Don't update complex children
							/*
							$complexProperty = $this->CurrentMapping->Properties[$objectProperty->name];
							$mapping = self::$Mapping[$complexProperty->Type];
							$mapping->PrimaryColumn
							$this->CurrentQuery .= sprintf('%s="%s", ', $objectProperty->name, $class->getProperty($objectProperty->name)->getValue($object->Id));
							*/
						}
					}
				}
				else
				{
					if(in_array($objectProperty->name, $keys))
					{
						if($type == "int" || $type == "integer")
						{
							$this->CurrentQuery .= sprintf('%s=%s, ', $objectProperty->name, $class->getProperty($objectProperty->name)->getValue($object));
						}
						else
						{
							if($property->IsComplex == false)
							{
								$this->CurrentQuery .= sprintf('%s="%s", ', $objectProperty->name, $class->getProperty($objectProperty->name)->getValue($object));
							}
							else
							{
								//The value $fieldToUpdate[$objectProperty->name] have to be the unique identifier of complex object
								$this->CurrentQuery .= sprintf('%s="%s", ', $objectProperty->name, $fieldToUpdate[$objectProperty->name]);
							}
						}
					}
				}
			}
		}
	
		$this->CurrentQuery = rtrim( $this->CurrentQuery , ", ");
		$this->CurrentQuery .= sprintf(' where %s=%s', $primaryKey, $class->getProperty($primaryKey)->getValue($object));
		
		Core\CoreCommons\Logger::Debug("Update query : " . $this->CurrentQuery);
			
		$result = mysql_query($this->CurrentQuery);
		
		if($result == false)
		{
			throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
		}
		
		return $object;
	}
	
	/**
	* Delete the entity on the database
	*
	* @param object $object The object to delete
	*
	* @return integer Return the number of affected row in database
	*/
	public function Delete($object)
	{
		$response = false;
		
		if(isset($object) == false)
		{
			throw new \Exception("Session - Delete => The object parameter is null.");
		}
		
		if(isset($object->Id))
		{
			$classname = get_class($object);

			if (preg_match('@\\\\([\w]+)$@', $classname, $matches)) {
				$classname = $matches[1];
			}

			$this->CurrentEntity = $classname;
		
			$table = $this->GetTable();
		
			$primaryKey = $this->GetPrimaryKey();
			
			$this->CurrentQuery = sprintf('delete from %s where %s = %u', $table, $primaryKey, $object->Id);
			
			Core\CoreCommons\Logger::Debug("Delete query : " . $this->CurrentQuery);
			
			$result = mysql_query($this->CurrentQuery);

			if($result == false)
			{
				throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
			}
			
			$response = mysql_affected_rows();
		}
		else
		{
			$response = false;
			Core\CoreCommons\Logger::Warning("Delete query : L'objet ne comporte pas de propriété Id.");
		}

		return $response;
	}
	
	/**
	* Get the table name
	*
	* @return string Return the table name related to the current entity
	*/
	private function GetTable($entity = null)
	{
		$result = null;
		try
		{
			if($entity == null)
			{
				$result = self::$Mapping[$this->CurrentEntity]->Table;
			}
			else if(isset(self::$Mapping[$entity]))
			{
				
				$result = self::$Mapping[$entity]->Table;
			}
			else
			{
				throw new \Exception("$this->CurrentEntity || $entity : is not on self mapping");
			}
		}
		catch(\Exception $ex)
		{
			Core\CoreCommons\Logger::Error($ex->getMessage());
		}
		return $result;
	}
	
	/**
	* Get the primary key
	*
	* @return string Return the primary key related to the current entity
	*/
	private function GetPrimaryKey($entity = null)
	{
		$result = null;
		if($entity == null)
		{
			$result = self::$Mapping[$this->CurrentEntity]->PrimaryColumn;
		}
		else if(isset(self::$Mapping[$entity]))
		{
			$result = self::$Mapping[$entity]->PrimaryColumn;
		}
		
		return $result;
	}
	
	/**
	* Get the column name
	*
	* @param string $property The property related to the column
	*
	* @return string Return the column name related to the property
	*/
	private function GetColumn($property)
	{
		if(isset($property) == false)
		{
			throw new \Exception("Session - GetColumn => The property parameter is null.");
		}
	
		$mapping = self::$Mapping[$this->CurrentEntity];
		return $mapping->Properties[$property];
	}
	
	/**
	* Get all properties of the current entity
	*
	* @return array The properties of the current entities
	*/
	private function GetProperties()
	{
		$mapping = self::$Mapping[$this->CurrentEntity];
		return $mapping->Properties;
	}
	
	/**
	* Get the property type of the property
	*
	* @param string $property The property to return his type
	*
	* @return string The property type of the current entities
	*/
	private function GetPropertyType($property)
	{
		$result = null;
		if(isset($property) == false)
		{
			throw new \Exception("Session - GetPropertyType => The property parameter is null.");
		}
		
		if (preg_match('/@property\s+([^\s]+)/', $property->getDocComment(), $matches)) 
		{
			list(, $type) = $matches;
			$result = $type;
		}
		return $result;
	}
	
	/**
	* Get the joints from an entity
	*
	* @return string The joints of the entity
	*/
	private function GetJoints()
	{
		//Check if the current entity has any complex properties
		$mapping = self::$Mapping[$this->CurrentEntity];
		foreach($mapping->Properties as $property)
		{
			if($property->IsComplex == true)
			{
				//Create the joint
				$complexPropertyMapping = self::$Mapping[$property->Type];
				$complexTableName = $complexPropertyMapping->Table;
				$complexAlias = $mapping->Properties[$property->Name]->Alias;
				$alias = $mapping->AliasTable;
				$complexPrimaryKey = $this->GetPrimaryKey($property->Type);
				
				if($complexTableName != null)
				{
					$joints =  sprintf(" inner join %s %s on %s.%s = %s.%s ", $complexTableName, $complexAlias, $complexAlias, $complexPrimaryKey, $alias, $property->Name);
					Core\CoreCommons\Logger::Debug("Add joint : " . $joints);
					$this->CurrentQuery .= $joints;
				}
			}
		}
	}
	
	/**
	* Get all columns from an entity
	*
	* @param mixed $entity The impacted entity 
	* @param string $fromAlias The new alias in several types in one type case (ex : Materail has 2 USER type on mapping)
	*
	* @return string The SQL columns request part
	*/
	private function GetColumns($entity = null, $forcedAlias = null)
	{
		$columns = "";
		$mapping = null;
		$alias = null;
		
		if($entity == null)
		{
			Core\CoreCommons\Logger::Debug("Get columns of $this->CurrentEntity");
			$mapping = self::$Mapping[$this->CurrentEntity];
			$alias = $mapping->AliasTable;
		}
		else if(isset(self::$Mapping[$entity]))
		{
			Core\CoreCommons\Logger::Debug("Get columns of $entity");
			$mapping = self::$Mapping[$entity];
			$alias = $mapping->AliasTable;
		}
		else
		{
			Core\CoreCommons\Logger::Warning("The entity $entity not matches with mapping");
			return "";
		}
		
		Core\CoreCommons\Logger::Debug("The computed alias of $this->CurrentEntity is $alias");
		
		foreach($mapping->Properties as $property)
		{
			if($property->IsComplex == true)
			{
				//Check all method calls with argument $property->Name to be replace by 
				$others = $this->GetColumns($property->Type, $property->Alias);
				$columns .= sprintf('%s,', $others);
			}
			else
			{
				if(isset($forcedAlias) == false)
				{
					$columns .= sprintf('%s.%s as %s_%s,', $property->Alias, $property->Column, $property->Column, $property->Alias);
				}
				else
				{
					$columns .= sprintf('%s.%s as %s_%s,', $forcedAlias, $property->Column, $property->Column, $forcedAlias);
				}
			}
		}
		
		Core\CoreCommons\Logger::Debug("The computed columns for $this->CurrentEntity is " . rtrim($columns, ","));
		
		return rtrim($columns, ",");
	}
	
	/**
	* Execute the current SQL query
	*
	* @return object The request result 
	*/
	private function ExecuteSQL()
	{
		Core\CoreCommons\Logger::Debug("Execute query : " . $this->CurrentQuery);
		//Execute the request
		$result = mysql_query($this->CurrentQuery);
		
		if($result == false)
		{
			throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
		}
		
		//Evaluate the number of result
		$numberResult = mysql_num_rows($result);
		
		Core\CoreCommons\Logger::Debug("There is  $numberResult impacted row(s)");
		
		$response = null;
		
		if($numberResult > 1)
		{
			throw new \Exception("The result contains more than 1 row.");
		}
		
		if($numberResult > 0)
		{
			$row = mysql_fetch_assoc($result);

			$ref = new \ReflectionClass("Core\CoreContracts\\" . $this->CurrentEntity); 
			$objectProperties = $ref->getProperties(\ReflectionProperty::IS_PUBLIC);
			$object = $ref->newInstanceArgs();
			for($i = 0; $i <= (count($objectProperties) - 1); $i++)
			{
				$objectProperty = $objectProperties[$i];
				$columnNameAliased= $this->GetColumnNameWithAlias($objectProperty->name);
				
				//If column type is blob set base64_encode threatment
				if($this->GetPropertyType($objectProperty) == "blob")
				{
					$objectProperty->setValue($object, base64_encode($row[$columnNameAliased]));
				}
				else
				{
					$objectProperty->setValue($object, $row[$columnNameAliased]);
				}
			}
			$response = $object;
			
			mysql_free_result($result);
		}
		
		return $response;
	}
	
	/**
	* Execute the current SQL query
	*
	* @return object The request result 
	*/
	private function ExecuteListSQL()
	{
		Core\CoreCommons\Logger::Debug("Execute list query : " . $this->CurrentQuery);
		
		if(isset($this->CurrentMapping) == false)
		{
			throw new \Exception("The current mapping is not set");
		}
		
		//Execute the request
		$result = mysql_query($this->CurrentQuery);
		
		if($result == false)
		{
			throw new \Exception(sprintf("%u : %s", mysql_errno(), mysql_error()));
		}
		
		//Evaluate the number of result
		$numberResult = mysql_num_rows($result);
		
		Core\CoreCommons\Logger::Debug("There is  $numberResult impacted row(s)");

		$response = array();
		while ($row = mysql_fetch_assoc($result)) 
		{
			$ref = new \ReflectionClass("Core\CoreContracts\\" . $this->CurrentEntity); 
			$objectProperties = $ref->getProperties(\ReflectionProperty::IS_PUBLIC);
			$object = $ref->newInstanceArgs();
			
			for($i = 0; $i <= (count($objectProperties) - 1); $i++)
			{
				$objectProperty = $objectProperties[$i];
				
				$property = $this->CurrentMapping->Properties[$objectProperty->name];
				
				if($property->IsComplex == false)
				{
					$columnNameAliased= $this->GetColumnNameWithAlias($objectProperty->name);
					//If column type is blob set base64_encode threatment
					if($this->GetPropertyType($objectProperty) == "blob")
					{
						$objectProperty->setValue($object, base64_encode($row[$columnNameAliased]));
					}
					else
					{
						$objectProperty->setValue($object, $row[$columnNameAliased]);
					}
				}
				else
				{
					Core\CoreCommons\Logger::Info("ExecuteListSQL - detect a complex property $property->Name");
					
					$complexObjectAlias = $property->Alias;
					$complexObject = $this->SetComplexObjectValues($this->GetPropertyType($objectProperty), $objectProperty->name, $row, $complexObjectAlias);
					$objectProperty->setValue($object, $complexObject);
				}
			}
			array_push($response, $object);
		}
		
		Core\CoreCommons\Logger::Debug("There is " . count($response) . " object created");
		
		mysql_free_result($result);
		
		return $response;
	}
	
	/**
	*  ex : $complexObjectTypeName : User / $complexObjectName : AffectedUser / $rows : fecthed rows from DB / $alias : ent_10
	* 
	*
	*/
	private function SetComplexObjectValues($complexObjectTypeName, $complexObjectName, $rows, $complexObjectAlias)
	{
		Core\CoreCommons\Logger::Info("SetComplexObjectValues - $complexObjectTypeName, $complexObjectName, $complexObjectAlias ");
		//create an instance of the complex object
		$class = new \ReflectionClass("Core\CoreContracts\\" . $complexObjectTypeName); 
		$objectProperties = $class->getProperties(\ReflectionProperty::IS_PUBLIC);
		$object = $class->newInstanceArgs();
			
		//Set his values
		for($i = 0; $i <= (count($objectProperties) - 1); $i++)
		{
			$objectProperty = $objectProperties[$i];
			$columnNameAliased = sprintf("%s_%s", $objectProperty->name, $complexObjectAlias);
			if(isset($rows[$columnNameAliased]))
			{
				//If column type is blob set base64_encode threatment
				if($this->GetPropertyType($objectProperty) == "blob")
				{
					$objectProperty->setValue($object, base64_encode($rows[$columnNameAliased]));
				}
				else
				{
					$objectProperty->setValue($object, $rows[$columnNameAliased]);
				}
			}
			else
			{
				Core\CoreCommons\Logger::Error("$columnNameAliased was not found on the rows result.");
			}
		}
	
		return $object;
	}
	
	/**
	* Build the column name with his alias
	*
	* @return string The column name with his alias
	*/
	private function GetColumnNameWithAlias($columnName, $entity = null)
	{
		$mapping = null;
		$alias = null;
		if(isset($entity))
		{
			//Core\CoreCommons\Logger::Debug(sprintf("GetColumnNameWithAlias from column name %s from entity %s", $columnName, $entity));
			$mapping = self::$Mapping[$entity];
		}
		else
		{
			//Core\CoreCommons\Logger::Debug(sprintf("GetColumnNameWithAlias from column name %s from entity %s", $columnName, $this->CurrentEntity));
			$mapping = self::$Mapping[$this->CurrentEntity];
		}
		
		$alias = $this->CurrentMapping->Properties[$columnName]->Alias;
		
		return sprintf("%s_%s", $columnName, $alias);
	}
	
	/**
	* Build the crietria SQL part, 'where' part
	*/
	private function GetCriterias()
	{
		if(count($this->Criterias) > 0)
		{
			$this->CurrentQuery .= ' where ';
			
			for($i = 0; $i <= (count($this->Criterias) - 1); $i++)
			{
				$criteria = $this->Criterias[$i];

				if($i < count($this->Criterias) - 1)
				{
					$this->CurrentQuery .= sprintf(' %s and ', $criteria);
				}
				else
				{	
					$this->CurrentQuery .= sprintf(' %s', $criteria);
				}
			}
		}
	}
}
?> 